package com.atguigu.dev;

import java.util.concurrent.TimeUnit;

class Phone {
    public static synchronized void sendEmail() {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("--------->sendEmail");
    }

    public static synchronized void callSomeBody() {
        System.out.println("--------->callSomeBody");
    }

    public synchronized void sendSMS() {
        System.out.println("--------->sendSMS");

    }

    public void hello() {
        System.out.println("--------->sayHello");
    }
}

public class Lock8Demo {
    /*    多线程锁的情况，它到底锁定的是什么？
     *
     * 答：synchronized是实现同步锁的基础，Java中的每一个对象都可以作为锁。
     *
     *
     * 1 标准访问，请问先打印邮件还是短信？ 邮件
     * 2 邮件暂停4秒钟，请问先打印邮件还是短信？邮件
     * 1-2总结
     *  一个对象里面如果有多个synchronized方法，某一个时刻内，只要有一个线程去调用其中的一个synchronized方法了
     *
     * 其他的线程都只能等待，换句话说，只能有唯一一个线程去方法这些synchronized方法
     * 锁的是当前对象this，被锁定后，其他的线程都不能进入当前对象的其他的synchronized方法
     *
     *
     * 3 新增普通hello方法，请问先打印邮件还是hello？    hello
     * 4 两部手机，请问先打印邮件还是短信？              短信
     *3-4总结
     *  加上了普通方法hello后发现和同步锁无关，被锁定后，其他的线程都不能进入到当前对象的其他的synchronized方法
     * 换成两个对象后，不是同一把锁了，两个不同的实例对象互不影响
     *
     * 5 两个静态同步方法，1部手机，请问先打印邮件还是短信？
     * 静态方法锁的是类级别的，而不是对象级别的。这意味着它们共享同一个锁。
     * 因此，如果T1线程正在执行sendEmail(),则T2线程将无法执行sendSMS(),直到T1线程释放锁。
     * 6 两个静态同步方法，2部手机，请问先打印邮件还是短信？
     * 即使是不同的Phone实例，静态方法依然共享类级别的锁，因此，即使T1和T2分别持有不同的Phone实例，它们仍然会互相阻塞对方的静态同步方法的执行。
     * 5-6总结
     * 若是普通同步方法，new this，具体的一部部手机，所有的普通同步方法用的都是同一把锁
     * 若是静态同步方法，static Class 唯一的一个模板，手机厂商的所有静态同步方法
     *
     *
     *
     * 7 1个静态同步方法，1个普通同步方法,1部手机，请问先打印邮件还是短信？短信
     * 8 1个静态同步方法，1个普通同步方法,2部手机，请问先打印邮件还是短信？短信
     *
     * 静态同步方法和普通同步方法锁的对象不同
     *静态同步方法锁的是类对象
     * 普通同步方法锁的是实例对象
     * */


    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> {
            phone1.sendEmail();
        }, "T1").start();
        try {
            TimeUnit.MILLISECONDS.sleep(200);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        new Thread(() -> {
//            phone1.sendSMS();
//            phone1.hello();
            phone1.sendSMS();
        }, "T2").start();
        try {
            TimeUnit.MILLISECONDS.sleep(200);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        new Thread(() -> {
            phone1.callSomeBody();
        }, "T3").start();
    }
}
